class CanvasApp {
    constructor(canvas) {
        this.canvas = canvas;
        this.context = canvas.getContext("2d");

        window.addEventListener("load", this.onWindowLoad.bind(this));
        window.addEventListener("resize", this.onWindowResize.bind(this));

        requestAnimationFrame(this.draw.bind(this));
        this.resizeCanvas();
    }

    onWindowLoad(event) {
        this.resizeCanvas();
    }

    onWindowResize(event) {
        this.resizeCanvas();
    }

    resizeCanvas() {
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight;
    }

    draw() {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        requestAnimationFrame(this.draw.bind(this));
    }
}

class ImageViewer extends CanvasApp {
    constructor(canvas, imageUrl1, imageUrl2) {
        super(canvas);

        this.imageUrl1 = imageUrl1;
        this.image1 = new ImageX(this, imageUrl1);

        this.imageUrl2 = imageUrl2;
        this.image2 = new ImageX(this, imageUrl2);

        this.splitter = this.canvas.width / 2.0;

        this.canvas.addEventListener("mousedown", this.onMouseDown.bind(this));
        this.canvas.addEventListener("mouseup", this.onMouseUp.bind(this));
        this.canvas.addEventListener("mousemove", this.onMouseMove.bind(this));
        this.canvas.addEventListener("wheel", this.onWheel.bind(this));

    }

    onWindowResize(event) {
        super.onWindowResize(event);

        this.image1.reset();
        this.image2.reset();

        this.splitter = this.canvas.width / 2.0;
    }

    onMouseDown(event) {
        if (event.buttons == 1) {
            this.splitter = event.clientX;
            this.canvas.style.cursor = "w-resize";            
        } else if (event.buttons == 4) {
            this.canvas.style.cursor = "move";
        }
    }

    onMouseUp(event) {
        this.canvas.style.cursor = "default";
    }
    
    onMouseMove(event) {
        if (event.buttons == 1) {  // Left button
            this.splitter = event.clientX;
        } else if (event.buttons == 4) {  // Middle button
            this.image1.translateBy(event.movementX, event.movementY);
            this.image2.translateBy(event.movementX, event.movementY);
        }
    }

    onWheel(event) {
        const delta = event.deltaY < 0 ? 1.1 : 0.9;
        this.image1.scaleBy(delta, event.clientX, event.clientY);
        this.image2.scaleBy(delta, event.clientX, event.clientY);
    }

    draw() {
        super.draw();

        this.drawImage(this.image1);
        this.drawImage(this.image2);

        this.drawSplitter();
        this.drawInformation();
    }

    drawImage(image) {
        if (image == undefined) {
            return;
        }

        const context = this.context;

        context.save();
        context.beginPath();

        let x = 0;
        let width = this.splitter;
        if (image == this.image2) {
            x = this.splitter;
            width = this.canvas.width - this.splitter;
        }
        context.rect(x, 0, width, this.canvas.height);

        context.clip();

        image.draw();
        context.restore();
    }

    drawSplitter() {
        const context = this.context;

        context.strokeStyle = "white";
        context.lineWidth = 0.5;

        context.beginPath();
        context.moveTo(this.splitter, 0);
        context.lineTo(this.splitter, this.canvas.height);
        context.stroke();
    }

    drawInformation() {
        const context = this.context;
        context.save();

        context.font = "12pt 微软雅黑";
        context.fillStyle = "white";
        context.globalCompositeOperation = "difference";

        context.fillText("使用说明：左键按下移动分割线，中键按下移动图像，鼠标滚轮缩放图像。", 20, 30);
        context.fillText("左边图像：" + this.imageUrl1, 20, 60);
        context.fillText("右边图像：" + this.imageUrl2, 20, 90);

        context.restore();
    }
}

class ImageX {
    constructor(imageViewer, imageUrl) {
        this.canvas = imageViewer.canvas;
        this.context = imageViewer.context;

        this.image = new Image();
        this.image.addEventListener("load", this.onImageLoad.bind(this));
        this.image.src = imageUrl;

        this.translateX = 0.0;
        this.translateY = 0.0;
        this.scale = 1.0;
    }

    onImageLoad(event) {
        this.reset();
    }


    translateBy(movementX, movementY) {
        this.translateX += movementX;
        this.translateY += movementY;
    }

    scaleBy(delta, clientX, clientY) {
        const dx = (this.translateX - clientX) / this.scale;
        const dy = (this.translateY - clientY) / this.scale;

        this.scale *= delta;

        this.translateX = clientX + dx * this.scale;
        this.translateY = clientY + dy * this.scale;
    }

    reset() {
        const canvas = this.canvas;
        const image = this.image;

        const scale = canvas.height / image.height;
        this.translateX = (canvas.width - image.width * scale) / 2.0;
        this.translateY = (canvas.height - image.height * scale) / 2.0;
        this.scale = scale;
    }


    draw() {
        if (this.image == undefined) {
            return;
        }

        const context = this.context;
        context.translate(this.translateX, this.translateY);
        context.scale(this.scale, this.scale);
        context.drawImage(this.image, 0, 0, this.image.width, this.image.height);
        context.resetTransform();
    }
}

const canvas = document.querySelector('canvas');
const viewer = new ImageViewer(canvas, "images/girl_1.png", "images/girl_2.png");
